package service

import (
	"bytes"
	"crypto/rand"
	"fmt"
	"image"
	"image/color"
	"image/draw"
	"image/jpeg"
	"math/big"
	"time"

	"github.com/gomodule/redigo/redis"
	"github.com/juexin/gin-base/internal/config"
	"golang.org/x/image/font"
	"golang.org/x/image/font/basicfont"
	"golang.org/x/image/math/fixed"
)

type CaptchaService struct {
	cfg       *config.Config
	redisPool *redis.Pool
}

func NewCaptchaService(cfg *config.Config, redisPool *redis.Pool) *CaptchaService {
	return &CaptchaService{
		cfg:       cfg,
		redisPool: redisPool,
	}
}

// 请求和响应结构体
type CaptchaResult struct {
	CaptchaID string `json:"captcha_id"`
	Image     []byte `json:"image"`
}

type CaptchaVerifyRequest struct {
	CaptchaID string `json:"captcha_id" binding:"required"`
	Code      string `json:"code" binding:"required"`
}

// GenerateCaptcha 生成图形验证码
func (s *CaptchaService) GenerateCaptcha() (*CaptchaResult, error) {
	// 生成随机验证码
	code := s.generateRandomCode(4)

	// 生成验证码图片
	img, err := s.generateCaptchaImage(code)
	if err != nil {
		return nil, err
	}

	// 将图片转换为字节数组
	var buf bytes.Buffer
	if err := jpeg.Encode(&buf, img, &jpeg.Options{Quality: 80}); err != nil {
		return nil, err
	}

	// 生成验证码ID
	captchaID := fmt.Sprintf("captcha_%d", time.Now().UnixNano())

	// 存储验证码到Redis
	conn := s.redisPool.Get()
	defer conn.Close()

	key := fmt.Sprintf("captcha:%s", captchaID)
	_, err = conn.Do("SETEX", key, 300, code) // 5分钟过期
	if err != nil {
		return nil, err
	}

	return &CaptchaResult{
		CaptchaID: captchaID,
		Image:     buf.Bytes(),
	}, nil
}

// VerifyCaptcha 验证图形验证码
func (s *CaptchaService) VerifyCaptcha(req *CaptchaVerifyRequest) error {
	conn := s.redisPool.Get()
	defer conn.Close()

	// 获取存储的验证码
	key := fmt.Sprintf("captcha:%s", req.CaptchaID)
	storedCode, err := redis.String(conn.Do("GET", key))
	if err != nil {
		if err == redis.ErrNil {
			return fmt.Errorf("验证码已过期或不存在")
		}
		return fmt.Errorf("获取验证码失败")
	}

	// 验证验证码（不区分大小写）
	if storedCode != req.Code {
		return fmt.Errorf("验证码错误")
	}

	// 验证成功，删除验证码
	conn.Do("DEL", key)

	return nil
}

// generateRandomCode 生成随机验证码
func (s *CaptchaService) generateRandomCode(length int) string {
	const charset = "0123456789"
	b := make([]byte, length)
	for i := range b {
		n, _ := rand.Int(rand.Reader, big.NewInt(int64(len(charset))))
		b[i] = charset[n.Int64()]
	}
	return string(b)
}

// generateCaptchaImage 生成验证码图片
func (s *CaptchaService) generateCaptchaImage(code string) (image.Image, error) {
	const width, height = 120, 40

	// 创建图片
	img := image.NewRGBA(image.Rect(0, 0, width, height))

	// 填充背景色
	bgColor := color.RGBA{240, 240, 240, 255}
	draw.Draw(img, img.Bounds(), &image.Uniform{bgColor}, image.Point{}, draw.Src)

	// 设置字体颜色
	textColor := color.RGBA{0, 0, 0, 255}

	// 绘制文字
	point := fixed.Point26_6{
		X: fixed.Int26_6(20 * 64),
		Y: fixed.Int26_6(25 * 64),
	}

	d := &font.Drawer{
		Dst:  img,
		Src:  image.NewUniform(textColor),
		Face: basicfont.Face7x13,
		Dot:  point,
	}

	// 绘制每个字符
	for i, c := range code {
		d.Dot = fixed.Point26_6{
			X: fixed.Int26_6((20 + i*20) * 64),
			Y: fixed.Int26_6(25 * 64),
		}
		d.DrawString(string(c))
	}

	// 添加干扰线
	s.addNoise(img, width, height)

	return img, nil
}

// addNoise 添加干扰线
func (s *CaptchaService) addNoise(img *image.RGBA, width, height int) {
	// 添加一些随机点
	for i := 0; i < 100; i++ {
		x, _ := rand.Int(rand.Reader, big.NewInt(int64(width)))
		y, _ := rand.Int(rand.Reader, big.NewInt(int64(height)))
		img.Set(int(x.Int64()), int(y.Int64()), color.RGBA{128, 128, 128, 255})
	}
}
